#include "nodo.h"

template <class Key, class Record>
bool TreeRecord<Key, Record>::inLeave = false;

template <class Key, class Record>
TreeRecord<Key, Record>::TreeRecord() : leave(inLeave), leftNode(0), rightNode(0) {}

template <class Key, class Record>
TreeRecord<Key, Record>::TreeRecord(bool leave) : leave(leave), leftNode(0), rightNode(0) {}

template <class Key, class Record>
bool TreeRecord<Key, Record>::isLeave(){
    return leave;
}

template <class Key, class Record>
void TreeRecord<Key, Record>::setLeave(bool leave){
    this->leave = leave;
}

template <class Key, class Record>
void TreeRecord<Key, Record>::read(BinaryStream& in){
    if (leave)
        record.read(in);
    else {
        leftNode = in.readPrimitive<u_int32_t>();
        key.read(in);
    }
}

template <class Key, class Record>
void TreeRecord<Key, Record>::write(BinaryStream& out){
    if (leave)
        record.write(out);
    else {
        out.writePrimitive<u_int32_t>(leftNode);
        key.write(out);
    }
}

template <class Key, class Record>
std::string TreeRecord<Key, Record>::toString(){
    std::stringstream sout;
    if (leave)
        sout << record.toString();
    else
        sout << leftNode << " (" << key.toString() << ")";
    return sout.str();
}

template <class Key, class Record>
Key TreeRecord<Key, Record>::getKey(){
    return leave ? record.getKey() : key;
}

template <class Key, class Record>
void TreeRecord<Key, Record>::setKey(Key key){
    this->key = key;
}

template <class Key, class Record>
Record TreeRecord<Key, Record>::getData(){
    return record;
}

template <class Key, class Record>
void TreeRecord<Key, Record>::setData(Record record){
    this->record = record;
}

template <class Key, class Record>
u_int32_t TreeRecord<Key, Record>::getLeftNode() {
    return leftNode;
}

template <class Key, class Record>
void TreeRecord<Key, Record>::setLeftNode(u_int32_t leftNode) {
    this->leftNode = leftNode;
}

template <class Key, class Record>
u_int32_t TreeRecord<Key, Record>::getRightNode() {
    return rightNode;
}

template <class Key, class Record>
void TreeRecord<Key, Record>::setRightNode(u_int32_t rightNode) {
    this->rightNode = rightNode;
}

template <class Key, class Record>
void TreeRecord<Key, Record>::setInLeave(bool inLeave){
    TreeRecord<Key, Record>::inLeave = inLeave;
}

template <class Key, class Record>
Node<Key, Record>::Node(u_int32_t blockSize) : Container<Key, TreeRecord<Key, Record> >(blockSize - 6) {
    level = 0;
    rightNode = 0;
}

template <class Key, class Record>
void Node<Key, Record>::read(BinaryStream& in) {
    // std::cout << "Read nodo..." << std::endl;
    level = in.readPrimitive<u_int16_t>();
    rightNode = in.readPrimitive<u_int32_t>();
    TreeRecord<Key, Record>::setInLeave(level == 0);
    Container<Key, TreeRecord<Key, Record> >::read(in);
    // std::cout << "Read nodo!" << std::endl;
}

template <class Key, class Record>
void Node<Key, Record>::write(BinaryStream& out){
    out.writePrimitive<u_int16_t>(level);
    out.writePrimitive<u_int32_t>(rightNode);
    Container<Key, TreeRecord<Key, Record> >::write(out);
}

template <class Key, class Record>
bool Node<Key, Record>::isLeave(){
    return level == 0;
}

template <class Key, class Record>
u_int16_t Node<Key, Record>::getLevel() {
    return level;
}

template <class Key, class Record>
void Node<Key, Record>::setLevel(u_int16_t level) {
    this->level = level;
}

template <class Key, class Record>
u_int32_t Node<Key, Record>::getRightNode(){
    return rightNode;
}

template <class Key, class Record>
void Node<Key, Record>::setRightNode(u_int32_t rightNode){
    this->rightNode = rightNode;
}

template <class Key, class Record>
u_int32_t Node<Key, Record>::getNodeNumber(){
    return nodeNumber;
}

template <class Key, class Record>
void Node<Key, Record>::setNodeNumber(u_int32_t nodeNumber){
    this->nodeNumber = nodeNumber;
}

template <class Key, class Record>
bool Node<Key, Record>::add(TreeRecord<Key, Record> record, bool ignoreSize){
    bool success = Container<Key, TreeRecord<Key, Record> >::add(record, ignoreSize);

    if (success && ! isLeave()) {
        auto it = find(record.getKey(), false);
        if (it != this->records.end()) {
            auto reg = *it;
            this->records.erase(it);
            reg.setLeftNode(record.getRightNode());
            this->records.insert(it, reg);
        } else {
            setRightNode(record.getRightNode());
        }
    }
    return success;
}

template <class Key, class Record>
u_int32_t Node<Key, Record>::getDescendant(Key key) {
    if (isLeave())
        throw -2;
    auto it = find(key, false);
    if (it == this->records.end())
        return rightNode;
    return (*it).getLeftNode();
}

template <class Key, class Record>
std::string Node<Key, Record>::toString(){
    std::stringstream sout;
    sout << Container<Key, TreeRecord<Key, Record> >::toString() << rightNode;
    return sout.str();
}
